home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993 October: Windmill on DISC / ADC Developer CD (1993-10) (''Windmill On DISC'')_iso / Dev.CD Oct 93.iso / System Software / U.S. System Software / System 7 Pro™ Beta 11 / Development Tools / Sample Code / Standard Mail / CollaboDraw (w⁄DigiSign) / draw.window.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-11  |  39.3 KB  |  1,672 lines  |  [TEXT/MPS ]

  1. /*-------------------------------------------------------------------------------------
  2.  *
  3.  * Simple Sample AOCE Application Framework
  4.  *
  5.  * ©1991-1993 Apple Computer
  6.  *
  7.  -------------------------------------------------------------------------------------*/
  8. /*
  9.  * draw.window.c -- window class instantiation/dispatching
  10.  *
  11.  * change history:
  12.  *
  13.  * SJF        04/21/93        1.0b2        update to b2
  14.  * SJF        03/01/93        1.0b1        added digital signatures
  15.  * SJF        02/09/93        1.0b1        update to b1
  16.  * SJF        10/13/92        1.0d4        update to a11
  17.  * SJF        09/09/92        1.0d3        update to a9
  18.  * SJF        05/07/92        1.0d2        update to a6
  19.  * SJF        11/06/91        1.0d1        initial coding
  20.  *
  21.  */
  22.  
  23. #ifndef __FILES__
  24. #include <Files.h>
  25. #endif
  26.  
  27. #ifndef __SCRIPT__
  28. #include <Script.h>
  29. #endif
  30.  
  31. #ifndef __ERRORS__
  32. #include <Errors.h>
  33. #endif
  34.  
  35. #ifndef __FOLDERS__
  36. #include <Folders.h>
  37. #endif
  38.  
  39. #ifndef __PACKAGES__
  40. #include <Packages.h>
  41. #endif
  42.  
  43. #ifndef __OCESTANDARDMAIL__
  44. #include <OCEStandardMail.h>
  45. #endif
  46.  
  47. #include "const.h"
  48. #include "strconst.h"
  49. #include "mytypes.h"
  50. #include "globals.h"
  51. #include "utils.h"
  52. #include "windowstuff.h"
  53. #include "mymenus.h"
  54. #include "digisig.h"
  55. #include "base.window.h"
  56. #include "windutils.h"
  57.  
  58. #include "draw.window.h"
  59.  
  60. #define kLineSlop        5
  61. #define    kSlop            2
  62. #define    kAnchorWidth    2
  63.  
  64. #define    abs(x)    (((x)<0) ? (-(x)) : (x))
  65.  
  66. /* instantiate a new draw window */
  67.  
  68. WindowPtr DrawMakeWindow(Rect *wRect,StringPtr title,Boolean visible,short wdefProc,Boolean goAwayFlag)
  69. {
  70.     WInfoPtr infoPtr;
  71.     WindowPtr theWindow;
  72.     char hState;
  73.     
  74.     theWindow = BaseMakeWindow(wRect,title,visible,wdefProc,goAwayFlag);
  75.     SetWindowKind(theWindow,kDrawWindow);
  76.  
  77.     infoPtr = BeginWindowAccess(theWindow,&hState);
  78.     
  79.     SetDrawMethods(infoPtr);
  80.     
  81.     // set other window information
  82.     infoPtr->data = nil;
  83.     infoPtr->otherData[kDSIGData] = nil;
  84.     
  85.     // make scroll bars
  86.     MakeScrollBars(theWindow,infoPtr);
  87.     
  88.     EndWindowAccess(theWindow,hState);
  89.     
  90.     return theWindow;
  91. }
  92.  
  93.  
  94. void SetDrawMethods(WInfoPtr infoPtr)
  95. {
  96.     infoPtr->m_idle = BaseIdleWindow;
  97.     infoPtr->m_fixCursor = DrawFixCursorWindow;
  98.     infoPtr->m_activate = DrawActivateWindow;
  99.     infoPtr->m_deactivate = DrawDeactivateWindow;
  100.     infoPtr->m_update = DrawUpdateWindow;
  101.     infoPtr->m_key = BaseKeyWindow;
  102.     infoPtr->m_resize = DrawResizeWindow;
  103.     infoPtr->m_click = DrawClickWindow;
  104.     infoPtr->m_destroy = DrawDestroyWindow;
  105.     infoPtr->m_undo = DrawUndoWindow;
  106.     infoPtr->m_cut = BaseCutWindow;
  107.     infoPtr->m_copy = BaseCopyWindow;
  108.     infoPtr->m_paste = BasePasteWindow;
  109.     infoPtr->m_clear = BaseClearWindow;
  110.     infoPtr->m_print = DrawPrintWindow;
  111.     infoPtr->m_pageSetup = DrawPageSetupWindow;
  112.     infoPtr->m_save = DrawSaveWindow;
  113.     infoPtr->m_load = DrawLoadWindow;
  114.     infoPtr->m_event = BaseEventWindow;
  115.     infoPtr->m_ctrlHit = DrawHitControlWindow;
  116.     infoPtr->m_selectAll = DrawSelectAllWindow;
  117.     infoPtr->m_group = DrawGroupWindow;
  118.     infoPtr->m_unGroup = DrawUnGroupWindow;
  119. }
  120.  
  121.  
  122. void *DrawFixCursorWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  123. {
  124.     RgnHandle returnRgn;
  125.     unsigned long *crsrData;
  126.     RgnHandle arrowRgn,pencilRgn;
  127.     Point offsetPt,mousePt;
  128.     GrafPtr savePort;
  129.     Rect drawRect;
  130.     
  131.     GetPort(&savePort);
  132.     SetPort(window);
  133.         
  134.     crsrData = (unsigned long *)data;
  135.     returnRgn = (RgnHandle)crsrData[1];
  136.     mousePt = *(Point *)&crsrData[0];
  137.     arrowRgn = NewRgn();
  138.     pencilRgn = NewRgn();
  139.     
  140.     drawRect = window->portRect;
  141.     drawRect.bottom -= 15;
  142.     drawRect.right -= 15;
  143.     
  144.     SetRectRgn(arrowRgn,-32768,-32768,32767,32767);
  145.     RectRgn(pencilRgn,&drawRect);
  146.     SetPt(&offsetPt,0,0);
  147.     LocalToGlobal(&offsetPt);
  148.     OffsetRgn(pencilRgn,offsetPt.h,offsetPt.v);
  149.     DiffRgn(arrowRgn,pencilRgn,arrowRgn);
  150.     
  151.     if (PtInRgn(mousePt,arrowRgn)) {
  152.         CopyRgn(arrowRgn,returnRgn);
  153.         SetCursor(&qd.arrow);
  154.     }
  155.     else if (PtInRgn(mousePt,pencilRgn)) {
  156.         CopyRgn(pencilRgn,returnRgn);
  157.         if (gCurrentShape!=kSelectShape)
  158.             SetCursor(&gPencilCursor);
  159.         else
  160.             SetCursor(&qd.arrow);
  161.     }
  162.  
  163.         
  164.     DisposeRgn(arrowRgn);
  165.     DisposeRgn(pencilRgn);
  166.     SetPort(savePort);
  167.     
  168.     return BaseFixCursorWindow(window,infoPtr,data);
  169. }
  170.  
  171.  
  172. void *DrawDestroyWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  173. {
  174.     ShapeListPtr shapeList,prevShape;
  175.     OSErr err;
  176.     
  177.     DSIGCloseFile(infoPtr);
  178.     
  179.     if (infoPtr->fRefNum) {
  180.         err = FSClose(infoPtr->fRefNum);
  181.         if (err!=noErr)
  182.             DoError(err);
  183.         infoPtr->fRefNum = 0;
  184.     }
  185.     
  186.     if (infoPtr->resRefNum) {
  187.         CloseResFile(infoPtr->resRefNum);
  188.         err = ResError();
  189.         if (err!=noErr)
  190.             DoError(err);
  191.         infoPtr->resRefNum = 0;
  192.     }
  193.         
  194.     shapeList = (ShapeListPtr) infoPtr->data;
  195.     while (shapeList) {
  196.         prevShape = shapeList;
  197.         shapeList = shapeList->next;
  198.         DisposPtrChk(prevShape);
  199.     }
  200.     
  201.     DisposeControl(VSCROLL);
  202.     DisposeControl(HSCROLL);
  203.     
  204.     return BaseDestroyWindow(window,infoPtr,data);
  205. }
  206.  
  207.  
  208. void *DrawUndoWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  209. {
  210.     #pragma unused (data)
  211.     if (!gCanUndo || window!=gUndoCommand.window) {
  212.         DoError(kInternalError);
  213.         return nil;
  214.     }
  215.     
  216.     if (gHasUndo) {    // we should redo
  217.         AddShape(gUndoCommand.theShape.shapeType,gUndoCommand.theShape.anchor,
  218.                 gUndoCommand.theShape.destination,nil,(ShapeListPtr *)&infoPtr->data,false);
  219.         InvalShapeArea(window,infoPtr,(ShapeListPtr)infoPtr->data);
  220.         gHasUndo = false;
  221.     }
  222.     else {
  223.         RemoveTopShape(window,infoPtr);
  224.         gHasUndo = true;
  225.     }
  226.     
  227.     SetupAppUndo();
  228.     return nil;
  229. }
  230.  
  231.  
  232. void *DrawActivateWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  233. {
  234.     MenuHandle theMenu;
  235.     
  236.     DisableAllMenus();
  237.     
  238.     theMenu = GetMHandle(kFileMenu);
  239.     EnableAllMenuItems(theMenu);
  240.     if (!infoPtr->changed)
  241.         DisableItem(theMenu,kSaveItem);
  242.             
  243.     /* only enable mail menu if we have AOCE */
  244.     
  245.     if (gHasAOCE) {
  246.         theMenu = GetMHandle(kMailMenu);
  247.         EnableAllMenuItems(theMenu);
  248.         DisableItem(theMenu,kSendItem);
  249.         DisableItem(theMenu,kReplyItem);
  250.         DisableItem(theMenu,kReplyToAllItem);
  251.         DisableItem(theMenu,kForwardItem);
  252.         DisableItem(theMenu,kTagLetterItem);
  253.     }
  254.     
  255.     FixDrawMenus(window,infoPtr);
  256.     
  257.     gMenusDirty = true;
  258.  
  259.     HiliteControl(VSCROLL,0);
  260.     HiliteControl(HSCROLL,0);
  261.  
  262.     return BaseActivateWindow(window,infoPtr,data);
  263. }
  264.  
  265.  
  266. void *DrawDeactivateWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  267. {
  268.     HiliteControl(VSCROLL,254);
  269.     HiliteControl(HSCROLL,254);
  270.  
  271.     return BaseDeactivateWindow(window,infoPtr,data);
  272. }
  273.  
  274.  
  275. void *DrawClickWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  276. {
  277.     GrafPtr savePort;
  278.     RgnHandle saveRgn,windowRgn;
  279.     MenuHandle theMenu;
  280.     
  281.     GetPort(&savePort);
  282.     SetPort(window);
  283.  
  284.     windowRgn = GetScrollersRgn(&window->portRect);
  285.     
  286.     saveRgn = NewRgn();
  287.     GetClip(saveRgn);
  288.     DiffRgn(saveRgn,windowRgn,windowRgn);
  289.     SetClip(windowRgn);
  290.  
  291.     if (gCurrentShape==kSelectShape) {
  292.         WarpExistingShape(window,infoPtr,((EventRecord *)data)->where,
  293.             (((EventRecord *)data)->modifiers & shiftKey)!=0);
  294.         ClearAppUndo();
  295.     }
  296.     else {
  297.         EnterNewShape(window,infoPtr,((EventRecord *)data)->where);
  298.     }
  299.     
  300.     SetClip(saveRgn);
  301.     DisposeRgn(saveRgn);    
  302.     DisposeRgn(windowRgn);
  303.     SetPort(savePort);
  304.  
  305.     FixDrawMenus(window,infoPtr);
  306.     theMenu = GetMHandle(kFileMenu);    // now we've changed, so the user can save
  307.     EnableItem(theMenu,kSaveItem);
  308.     
  309.     return BaseClickWindow(window,infoPtr,data);
  310. }
  311.  
  312.  
  313. void *DrawUpdateWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  314. {
  315.     RgnHandle saveRgn,windowRgn;
  316.     Point *scrollPos,offsetPos;
  317.     
  318.     scrollPos = (Point*)&infoPtr->otherData[kViewOffset];
  319.     offsetPos.h = infoPtr->leftIndent - scrollPos->h;
  320.     offsetPos.v = infoPtr->topIndent - scrollPos->v;
  321.     
  322.     saveRgn = NewRgn();
  323.     windowRgn = GetScrollersRgn(&window->portRect);
  324.  
  325.     GetClip(saveRgn);
  326.     DiffRgn(saveRgn,windowRgn,windowRgn);
  327.     SetClip(windowRgn);
  328.     
  329.     DrawAllShapes(infoPtr,offsetPos);
  330.     
  331.     SetClip(saveRgn);
  332.     DisposeRgn(saveRgn);
  333.     DisposeRgn(windowRgn);
  334.     
  335.     UpdtControl(window,window->visRgn);
  336.     
  337.     return BaseUpdateWindow(window,infoPtr,data);
  338. }
  339.  
  340.  
  341. void *DrawResizeWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  342. {    
  343.     #pragma unused (infoPtr)
  344.     Rect *oldSize,gbRect;
  345.     
  346.     oldSize = (Rect *)data;
  347.     gbRect = *oldSize;
  348.     gbRect.top = gbRect.bottom - kGrowBoxWidth;
  349.     gbRect.left = gbRect.right - kGrowBoxWidth;
  350.     EraseRect(&gbRect);
  351.  
  352.     MoveScrollBars(window);
  353.     
  354.     gbRect = window->portRect;
  355.     gbRect.top = gbRect.bottom - kGrowBoxWidth;
  356.     gbRect.left = gbRect.right - kGrowBoxWidth;
  357.     ValidRect(&gbRect);
  358.     MyDrawGrowIcon(window);
  359.  
  360.     return nil;
  361. }
  362.  
  363.  
  364. void *DrawPrintWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  365. {
  366.     #pragma unused (window,data)
  367.     Boolean shouldContinue;
  368.     TPPrPort thePrPort;
  369.     TPrStatus theStatus;
  370.     Point zeroOffset = {0,0};
  371.     
  372.     // open print driver
  373.     
  374.     PrOpen();
  375.     if (PrError()!=noErr) {
  376.         DoError(PrError());
  377.         return nil;
  378.     }
  379.     
  380.     // display print dialog
  381.     
  382.     SetCursor(&qd.arrow);
  383.     shouldContinue = PrJobDialog(infoPtr->printRecord);
  384.     if (PrError()!=noErr) {
  385.         DoError(PrError());
  386.         return nil;
  387.     }
  388.     if (!shouldContinue)
  389.         return nil;
  390.     
  391.     // init printing grafport
  392.     
  393.     thePrPort = PrOpenDoc(infoPtr->printRecord,nil,nil);
  394.     if (PrError()==noErr) {
  395.         PrOpenPage(thePrPort,nil);
  396.         if (PrError()==noErr)
  397.             DrawAllShapes(infoPtr,zeroOffset);
  398.         PrClosePage(thePrPort);
  399.     }
  400.     PrCloseDoc(thePrPort);
  401.     
  402.     if ((((TPPrint)*(infoPtr->printRecord))->prJob.bJDocLoop == bSpoolLoop) && (PrError() == noErr))
  403.         PrPicFile(infoPtr->printRecord, nil, nil, nil, &theStatus);                
  404.  
  405.     // close print driver
  406.     
  407.     PrClose();
  408.     
  409.     return nil;
  410. }
  411.  
  412.  
  413. void *DrawPageSetupWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  414. {
  415.     Boolean changed;
  416.     
  417.     changed = CheckPageSize(window,infoPtr);
  418.     if (!changed)
  419.         ReCalcScrollBars(window,infoPtr);
  420.  
  421.     return BasePageSetupWindow(window,infoPtr,data);
  422. }
  423.  
  424.  
  425. void *DrawSaveWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  426. {
  427.     OSErr err;
  428.     SMPSaveType saveHow;
  429.     short fRefNum,resRefNum;
  430.     
  431.     saveHow = (SMPSaveType)data;
  432.     
  433.     // handle save as
  434.     
  435.     if (saveHow==kSMPSaveAs) {
  436.     
  437.         // create the new file, deleting any existing file, as per user's std file request
  438.         
  439.         err = FSpCreate(&infoPtr->fileSpec,kAppCreator,kDrawingType,smRoman);
  440.         if (err==dupFNErr) {
  441.             FSpDelete(&infoPtr->fileSpec);
  442.             err = FSpCreate(&infoPtr->fileSpec,kAppCreator,kDrawingType,smRoman);
  443.         }
  444.         if (err!=noErr) {
  445.             DoError(err);
  446.             return nil;
  447.         }
  448.         FSpCreateResFile(&infoPtr->fileSpec,kAppCreator,kDrawingType,smRoman);
  449.         err = ResError();
  450.         if (err!=noErr) {
  451.             FSpDelete(&infoPtr->fileSpec);
  452.             DoError(err);
  453.             return nil;
  454.         }
  455.             
  456.         // open the new file (data fork)
  457.         
  458.         err = FSpOpenDF(&infoPtr->fileSpec,fsRdWrPerm,&fRefNum);
  459.         if (err!=noErr) {
  460.             FSpDelete(&infoPtr->fileSpec);
  461.             DoError(err);
  462.             return nil;
  463.         }
  464.         
  465.         // open the new file (resource fork)
  466.         
  467.         resRefNum = FSpOpenResFile(&infoPtr->fileSpec,fsRdWrPerm);
  468.         err = ResError();
  469.         if (err!=noErr) {
  470.             FSClose(fRefNum);
  471.             FSpDelete(&infoPtr->fileSpec);
  472.             DoError(err);
  473.             return nil;
  474.         }
  475.         
  476.         // close the old file, if it exists
  477.         
  478.         if (infoPtr->fRefNum)
  479.             FSClose(infoPtr->fRefNum);
  480.             
  481.         // store the new fRefNum into the document data structure
  482.         
  483.         infoPtr->fRefNum = fRefNum;
  484.     }
  485.     else
  486.         resRefNum = infoPtr->resRefNum;
  487.     
  488.     // add digital signature information
  489.     
  490.     DSIGSaveFile(infoPtr,resRefNum,false);
  491.     if (saveHow==kSMPSaveAs) {
  492.         if (infoPtr->resRefNum)
  493.             CloseResFile(infoPtr->resRefNum);
  494.         infoPtr->resRefNum = resRefNum;
  495.     }
  496.     
  497.     // save the actual file
  498.     
  499.     err = SaveDrawingToDisk(infoPtr->fRefNum,infoPtr);
  500.     if (err!=noErr) {
  501.         DoError(err);
  502.         return nil;
  503.     }
  504.     
  505.     SetWTitle(window,infoPtr->fileSpec.name);    
  506.     return BaseSaveWindow(window,infoPtr,data);
  507. }
  508.  
  509.  
  510. void *DrawLoadWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  511. {
  512.     OSErr err;
  513.     long count;
  514.     short fRefNum,resRefNum;
  515.     FSSpec *fSpec;
  516.     char hState;
  517.     
  518.     fSpec = data;
  519.     
  520.     // open the file.  we leave it open for reading and writing the whole time
  521.     // that we need to read stuff out of it.
  522.     
  523.     err = FSpOpenDF(fSpec,fsRdWrPerm,&fRefNum);    // we leave the file open
  524.     if (err!=noErr) {
  525.         DoError(err);
  526.         return nil;
  527.     }
  528.     infoPtr->fRefNum = fRefNum;
  529.     resRefNum = FSpOpenResFile(fSpec,fsRdWrPerm);
  530.     err = ResError();
  531.     if (err!=noErr) {
  532.         FSClose(fRefNum);
  533.         DoError(err);
  534.         return nil;
  535.     }
  536.     infoPtr->resRefNum = resRefNum;
  537.  
  538.     // read print record
  539.     
  540.     count = sizeof(TPrint);
  541.     hState = HGetState((Handle)infoPtr->printRecord);
  542.     HLock((Handle)infoPtr->printRecord);
  543.     err = FSRead(fRefNum,&count,*(infoPtr->printRecord));
  544.     HSetState((Handle)infoPtr->printRecord,hState);
  545.     if (err!=noErr) {
  546.         DoError(err);
  547.         return nil;
  548.     }
  549.     
  550.     // read shape information
  551.     
  552.     LoadShapesFromDisk(fRefNum,(ShapeListPtr *)&infoPtr->data);
  553.     
  554.     // do digital signature stuff
  555.     
  556.     DSIGOpenFile(infoPtr);
  557.     
  558.     BaseLoadWindow(window,infoPtr,data);
  559. }
  560.  
  561.  
  562. void *DrawHitControlWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  563. {
  564.     ControlHitMessage *msg;
  565.     short newValue,oldValue;
  566.     Point mousePos;
  567.     
  568.     msg = (ControlHitMessage *)data;
  569.     mousePos = msg->ev->where;
  570.     GlobalToLocal(&mousePos);
  571.     
  572.     switch (msg->part) {
  573.         case inPageUp:
  574.         case inPageDown:
  575.             TrackControl(msg->control,mousePos,(ProcPtr)ScrollActionProc);
  576.             break;
  577.         case inUpButton:
  578.         case inDownButton:
  579.             TrackControl(msg->control,mousePos,(ProcPtr)ScrollActionProc);
  580.             break;
  581.         case inThumb:
  582.             oldValue = GetCtlValue(msg->control);
  583.             if (TrackControl(msg->control,mousePos,nil)) {
  584.                 newValue = GetCtlValue(msg->control);
  585.                 if (oldValue!=newValue) {
  586.                     if (msg->control==(ControlHandle)VSCROLL)
  587.                         MoveGraphics(window,infoPtr,0,newValue-oldValue);
  588.                     else
  589.                         MoveGraphics(window,infoPtr,newValue-oldValue,0);
  590.                 }
  591.             }
  592.             break;
  593.     }
  594.         
  595.     return nil;
  596. }
  597.  
  598.  
  599. void *DrawSelectAllWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  600. {
  601.     ShapeListPtr shapeList;
  602.     
  603.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  604.         shapeList->selected = true;
  605.         InvalShapeArea(window,infoPtr,shapeList);
  606.     }
  607.     
  608.     FixDrawMenus(window,infoPtr);
  609. }
  610.  
  611.  
  612. void *DrawGroupWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  613. {
  614.     ShapeListPtr shapeList,prevShape,selectedShape;
  615.     ShapeListPtr groupList;
  616.     Point anchor,destination,emptyPt = {0,0};
  617.     
  618.     // put all selected shapes into groupList, pulling them out of shapeList
  619.     
  620.     groupList = nil;
  621.     shapeList = infoPtr->data;
  622.     prevShape = nil;        
  623.     while (shapeList!=nil) {
  624.         if (shapeList->selected) {
  625.             selectedShape = shapeList;
  626.             selectedShape->selected = false;
  627.             if (prevShape)
  628.                 prevShape->next = selectedShape->next;
  629.             else
  630.                 infoPtr->data = shapeList->next;
  631.             shapeList = shapeList->next;
  632.             selectedShape->next = groupList;
  633.             groupList = selectedShape;
  634.     
  635.         }
  636.         else {
  637.             prevShape = shapeList;
  638.             shapeList = shapeList->next;
  639.         }
  640.     }
  641.     
  642.     GetGroupBounds(groupList,&anchor,&destination);
  643.     shapeList = AddShape(kBeginGroupTag,anchor,destination,groupList,
  644.                         (ShapeListPtr *)&infoPtr->data,false);
  645.     shapeList->selected = true;
  646.     InvalShapeArea(window,infoPtr,shapeList);
  647.     ClearAppUndo();
  648.     FixDrawMenus(window,infoPtr);
  649.     
  650.     return BaseGroupWindow(window,infoPtr,data);
  651. }
  652.  
  653.  
  654. void *DrawUnGroupWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  655. {
  656.     ShapeListPtr shapeList,prevShape,selectedShape;
  657.     ShapeListPtr ungroupShapes;
  658.     
  659.     // put all group shapes into ungroupShapes, pulling them out of shapeList
  660.     
  661.     ungroupShapes = nil;
  662.     shapeList = infoPtr->data;
  663.     prevShape = nil;        
  664.     while (shapeList!=nil) {
  665.         if (shapeList->selected && shapeList->shapeType==kBeginGroupTag) {
  666.             selectedShape = shapeList;
  667.             selectedShape->selected = false;
  668.             if (prevShape)
  669.                 prevShape->next = selectedShape->next;
  670.             else
  671.                 infoPtr->data = shapeList->next;
  672.             shapeList = shapeList->next;
  673.             selectedShape->next = ungroupShapes;
  674.             ungroupShapes = selectedShape;
  675.     
  676.         }
  677.         else {
  678.             prevShape = shapeList;
  679.             shapeList = shapeList->next;
  680.         }
  681.     }
  682.     
  683.     // add all of the sub-group shapes into the shape list
  684.     
  685.     while (ungroupShapes!=nil) {
  686.         InvalShapeArea(window,infoPtr,ungroupShapes);
  687.         
  688.         shapeList = ungroupShapes->subList;
  689.         while (shapeList!=nil) {
  690.             selectedShape = shapeList;
  691.             selectedShape->selected = true;
  692.             shapeList = shapeList->next;
  693.             selectedShape->next = infoPtr->data;
  694.             infoPtr->data = selectedShape;
  695.         }
  696.         
  697.         shapeList = ungroupShapes;
  698.         if (shapeList->isSigned) {
  699.             shapeList->digSig->shouldDelete = true;    // invalidate the group obj digital signature
  700.             shapeList->digSig->shape = nil;
  701.         }
  702.         ungroupShapes = ungroupShapes->next;
  703.         DisposPtrChk(shapeList);
  704.     }
  705.     ClearAppUndo();
  706.     FixDrawMenus(window,infoPtr);
  707.             
  708.     return BaseUnGroupWindow(window,infoPtr,data);
  709. }
  710.  
  711.  
  712. /*------- non window-class stuff ---------*/
  713.  
  714.  
  715. /* let the user enter a new shape */
  716.  
  717. void EnterNewShape(WindowPtr window,WInfoPtr infoPtr,Point where)
  718. {
  719.     Point anchor,destination,offsetPos;
  720.     Point emptyPt = {0,0};
  721.     Point *scrollPos;
  722.     ShapeListPtr shapeList;
  723.     
  724.     scrollPos = (Point *)&infoPtr->otherData[kViewOffset];
  725.     anchor = where;
  726.     GlobalToLocal(&anchor);
  727.     destination = anchor;
  728.     
  729.     RubberBandShape(gCurrentShape,anchor,&destination,emptyPt);
  730.     DrawCurrentShape(gCurrentShape,anchor,destination,emptyPt);
  731.  
  732.     offsetPos.h = scrollPos->h-infoPtr->leftIndent;
  733.     offsetPos.v = scrollPos->v-infoPtr->topIndent;
  734.     
  735.     anchor.h += offsetPos.h;
  736.     anchor.v += offsetPos.v;
  737.     destination.h += offsetPos.h;
  738.     destination.v += offsetPos.v;
  739.  
  740.     for (shapeList = infoPtr->data; shapeList!=nil; shapeList = shapeList->next) {
  741.         if (shapeList->selected) {
  742.             shapeList->selected = false;
  743.             EraseAnchorPoints(shapeList,offsetPos);
  744.         }
  745.     }
  746.  
  747.     AddShape(gCurrentShape,anchor,destination,nil,
  748.                 (ShapeListPtr *)&infoPtr->data,false);
  749.     AddShapeUndo(gCurrentShape,anchor,destination,window,infoPtr);    
  750. }
  751.  
  752.  
  753. /* do the rubber band thing with either a new or existing shape */
  754.  
  755. void RubberBandShape(short shapeType,Point anchor,Point *retDestination,Point offset)
  756. {
  757.     RgnHandle prevRgn,newRgn,invRgn,opDiffRgn,swapRgn,innerRgn;
  758.     Point destination,newDest;
  759.     
  760.     destination = *retDestination;
  761.     
  762.     PenNormal();
  763.     switch (shapeType) {
  764.         case kLineShape:
  765.             PenMode(patXor);
  766.             DrawCurrentShape(shapeType,anchor,destination,offset);
  767.             while (WaitMouseUp()) {
  768.                 GetMouse(&newDest);
  769.                 newDest.h -= offset.h;
  770.                 newDest.v -= offset.v;
  771.                 if (!EqualPt(newDest,destination)) {
  772.                     DrawCurrentShape(shapeType,anchor,destination,offset);
  773.                     destination = newDest;
  774.                     DrawCurrentShape(shapeType,anchor,destination,offset);
  775.                 }
  776.             }
  777.             break;
  778.         default:
  779.             prevRgn = NewRgn();
  780.             newRgn = NewRgn();
  781.             invRgn = NewRgn();
  782.             opDiffRgn = NewRgn();
  783.             innerRgn = NewRgn();
  784.             
  785.             OpenRgn();
  786.             DrawCurrentShape(shapeType,anchor,destination,offset);
  787.             CloseRgn(prevRgn);
  788.             CopyRgn(prevRgn,innerRgn);
  789.             InsetRgn(innerRgn,1,1);
  790.             DiffRgn(prevRgn,innerRgn,prevRgn);
  791.             
  792.             InvertRgn(prevRgn);
  793.             EmptyRgn(newRgn);
  794.             
  795.             while (WaitMouseUp()) {
  796.                 GetMouse(&newDest);
  797.                 newDest.h -= offset.h;
  798.                 newDest.v -= offset.v;
  799.                 if (!EqualPt(newDest,destination)) {
  800.                     destination = newDest;
  801.                     
  802.                     OpenRgn();
  803.                     DrawCurrentShape(shapeType,anchor,destination,offset);
  804.                     CloseRgn(newRgn);
  805.                     CopyRgn(newRgn,innerRgn);
  806.                     InsetRgn(innerRgn,1,1);
  807.                     DiffRgn(newRgn,innerRgn,newRgn);
  808.                     
  809.                     DiffRgn(prevRgn,newRgn,invRgn);
  810.                     DiffRgn(newRgn,prevRgn,opDiffRgn);
  811.                     UnionRgn(invRgn,opDiffRgn,invRgn);
  812.                     InvertRgn(invRgn);
  813.                     swapRgn = prevRgn;
  814.                     prevRgn = newRgn;
  815.                     newRgn = swapRgn;
  816.                 }
  817.             }
  818.             InvertRgn(prevRgn);
  819.             DisposeRgn(prevRgn);
  820.             DisposeRgn(newRgn);
  821.             DisposeRgn(invRgn);
  822.             DisposeRgn(opDiffRgn);
  823.             DisposeRgn(innerRgn);
  824.             break;
  825.     }
  826.     
  827.     PenNormal();
  828.     *retDestination = destination;
  829. }
  830.     
  831.  
  832. /* select or move or stretch a shape that already exists */
  833.  
  834. void WarpExistingShape(WindowPtr window,WInfoPtr infoPtr,Point where,Boolean extendSelection)
  835. {
  836.     Point *scrollPos,offsetPos;
  837.     ShapeListPtr shapeList,otherList;
  838.     Boolean hitShape,wasSelected,warpedShape;
  839.     Point newDest,oldDest,firstDest;
  840.     
  841.     warpedShape = false;
  842.     hitShape = false;
  843.     wasSelected = false;
  844.     
  845.     // determine offsets due to scrolling, indent, global-local changes
  846.     
  847.     scrollPos = (Point *)&infoPtr->otherData[kViewOffset];
  848.     offsetPos.h = infoPtr->leftIndent - scrollPos->h;
  849.     offsetPos.v = infoPtr->topIndent - scrollPos->v;
  850.     GlobalToLocal(&where);
  851.  
  852.     // do hit testing
  853.     
  854.     shapeList = infoPtr->data;
  855.     while (shapeList && !hitShape) {
  856.         hitShape = CheckHitShape(window,infoPtr,offsetPos,where,shapeList,&warpedShape);
  857.         if (!hitShape)
  858.             shapeList = shapeList->next;
  859.     }
  860.     
  861.     
  862.     // mark shape selected
  863.  
  864.     if (hitShape) {
  865.         
  866.         if (shapeList->selected==false) {
  867.             wasSelected = false;
  868.             shapeList->selected = true;
  869.         }
  870.         else
  871.             wasSelected = true;
  872.     }
  873.         
  874.     // if shift wasn't held, unselect all other objects
  875.     
  876.     if ((extendSelection==false) && ((warpedShape==true) || (hitShape==false) || (wasSelected==false))) {
  877.         for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  878.             if (otherList->selected && (!hitShape || (otherList!=shapeList) || !shapeList->selected)) {
  879.                 otherList->selected = false;
  880.                 EraseAnchorPoints(otherList,offsetPos);
  881.             }
  882.         }
  883.     }
  884.  
  885.     if (hitShape) {
  886.     
  887.         for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  888.             if (otherList->selected) {
  889.                 InvalShapeArea(window,infoPtr,otherList);
  890.             }
  891.         }
  892.         
  893.         // do shape moving stuff
  894.         
  895.         GetMouse(&oldDest);
  896.         newDest = oldDest;
  897.         while (WaitMouseUp() && EqualPt(newDest,oldDest))
  898.             GetMouse(&newDest);
  899.         if (!EqualPt(newDest,oldDest)) {
  900.         
  901.             // draw shape in gray, since we're going to move it
  902.             
  903.             for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  904.                 if (otherList->selected) {
  905.                     PenPat(qd.gray);
  906.                     DrawShapeObject(otherList,offsetPos,false);
  907.                     PenPat(qd.black);
  908.                     PenMode(patXor);
  909.                     DrawShapeObject(otherList,offsetPos,false);
  910.                 }
  911.             }
  912.             
  913.             // move shape(s) here
  914.  
  915.             GetMouse(&firstDest);
  916.             newDest = firstDest;
  917.             while (WaitMouseUp()) {
  918.                 oldDest = newDest;
  919.                 GetMouse(&newDest);
  920.                 if (!EqualPt(oldDest,newDest)) {
  921.                     oldDest.h = offsetPos.h - firstDest.h + oldDest.h;
  922.                     oldDest.v = offsetPos.v - firstDest.v + oldDest.v;
  923.                     for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  924.                         if (otherList->selected)
  925.                             DrawShapeObject(otherList,oldDest,false);
  926.                     }
  927.                     oldDest.h = offsetPos.h - firstDest.h + newDest.h;
  928.                     oldDest.v = offsetPos.v - firstDest.v + newDest.v;
  929.                     for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  930.                         if (otherList->selected)
  931.                             DrawShapeObject(otherList,oldDest,false);
  932.                     }
  933.                 }
  934.             }
  935.             for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  936.                 if (otherList->selected) {
  937.                     OffsetShape(otherList,newDest.h-firstDest.h,newDest.v-firstDest.v);
  938.                     InvalShapeArea(window,infoPtr,otherList);
  939.                 }
  940.             }        
  941.  
  942.         }
  943.     }
  944.     
  945.     PenNormal();
  946. }
  947.  
  948.  
  949. /* perform a hit test on the object, returning whether the object was hit or should be warped */
  950.  
  951. Boolean CheckHitShape(WindowPtr window,WInfoPtr infoPtr,Point offsetPos,Point hitPt,ShapeListPtr theShape,Boolean *warp)
  952. {
  953.     RgnHandle shape,overShape;
  954.     Rect boundBox;
  955.     Boolean hitShape;
  956.     Point anchor,destination;
  957.     float slope,intercept,hitPoint;
  958.     ShapeListPtr groupList;
  959.     
  960.     hitShape = false;
  961.     *warp = false;
  962.     shape = NewRgn();
  963.     overShape = NewRgn();
  964.         
  965.     // check bounding box
  966.     
  967.     if (theShape->anchor.h < theShape->destination.h) {
  968.         boundBox.left = theShape->anchor.h;
  969.         boundBox.right = theShape->destination.h;
  970.     }
  971.     else {
  972.         boundBox.left = theShape->destination.h;
  973.         boundBox.right = theShape->anchor.h;
  974.     }
  975.     if (theShape->anchor.v < theShape->destination.v) {
  976.         boundBox.top = theShape->anchor.v;
  977.         boundBox.bottom = theShape->destination.v;
  978.     }
  979.     else {
  980.         boundBox.top = theShape->destination.v;
  981.         boundBox.bottom = theShape->anchor.v;
  982.     }
  983.     boundBox.top += offsetPos.v;
  984.     boundBox.bottom += offsetPos.v;
  985.     boundBox.left += offsetPos.h;
  986.     boundBox.right += offsetPos.h;    
  987.     InsetRect(&boundBox,-kSlop,-kSlop);
  988.  
  989.     // check hit in digital signature button
  990.     
  991.     if (DSIGHitShape(window,infoPtr,hitPt,offsetPos,theShape))
  992.         hitShape = false;
  993.             
  994.     // check hit in shape area
  995.     
  996.     else if (PtInRect(hitPt,&boundBox)) {
  997.         
  998.         // check hit on group shape
  999.                 
  1000.         if (theShape->shapeType==kBeginGroupTag) {
  1001.             if (CheckHitAnchor(theShape,hitPt,offsetPos,&anchor,&destination))
  1002.                 hitShape = true;
  1003.             else
  1004.                 for (groupList=theShape->subList; groupList!=nil && hitShape==false; groupList=groupList->next) {
  1005.                     if (CheckHitShape(window,infoPtr,offsetPos,hitPt,groupList,warp))
  1006.                         hitShape = true;
  1007.                 }
  1008.         }
  1009.         
  1010.         // check rubber banding (for warping an object)
  1011.  
  1012.         else if (CheckHitAnchor(theShape,hitPt,offsetPos,&anchor,&destination)) {
  1013.             PenPat(qd.gray);
  1014.             DrawShapeObject(theShape,offsetPos,false);
  1015.             PenPat(qd.black);
  1016.             InvalShapeArea(window,infoPtr,theShape);
  1017.             RubberBandShape(theShape->shapeType,anchor,&destination,offsetPos);
  1018.             theShape->anchor = anchor;
  1019.             theShape->destination = destination;
  1020.             InvalShapeArea(window,infoPtr,theShape);
  1021.             hitShape = true;
  1022.             *warp = true;
  1023.         }
  1024.         
  1025.         // check hit on an object -- line
  1026.  
  1027.         else if (theShape->shapeType==kLineShape) {
  1028.             hitPt.h -= offsetPos.h;
  1029.             hitPt.v -= offsetPos.v;
  1030.             if (theShape->anchor.h==theShape->destination.h) {
  1031.                 if ((theShape->anchor.h > hitPt.h-kLineSlop) && (theShape->anchor.h < hitPt.h+kLineSlop))
  1032.                     hitShape = true;
  1033.             }
  1034.             else {
  1035.                 slope = (float)(theShape->anchor.v-theShape->destination.v) / (float)(theShape->anchor.h-theShape->destination.h);
  1036.                 intercept = (float)theShape->anchor.v - (slope * (float)theShape->anchor.h);
  1037.                 hitPoint = (slope * (float)hitPt.h) + intercept;
  1038.                 if (((short)hitPoint > (hitPt.v-kLineSlop)) && ((short)hitPoint < (hitPt.v+kLineSlop)))
  1039.                     hitShape = true;
  1040.                 else {
  1041.                     hitPoint = ((float)hitPt.v - intercept) / slope;
  1042.                     if (((short)hitPoint > (hitPt.h-kLineSlop)) && ((short)hitPoint < (hitPt.h+kLineSlop)))
  1043.                         hitShape = true;
  1044.                 }
  1045.             }
  1046.         }
  1047.         
  1048.         // check hit on an object -- other
  1049.  
  1050.         else {
  1051.             OpenRgn();
  1052.             DrawShapeObject(theShape,offsetPos,false);
  1053.             CloseRgn(shape);
  1054.             CopyRgn(shape,overShape);
  1055.             InsetRgn(shape,kSlop,kSlop);
  1056.             InsetRgn(overShape,-kSlop,-kSlop);
  1057.             DiffRgn(overShape,shape,overShape);
  1058.             if (PtInRgn(hitPt,overShape))
  1059.                 hitShape = true;
  1060.         }
  1061.     }
  1062.  
  1063.     DisposeRgn(shape);
  1064.     DisposeRgn(overShape);
  1065.     return hitShape;
  1066. }
  1067.  
  1068.  
  1069. /* draws all the shapes */
  1070.  
  1071. void DrawAllShapes(WInfoPtr infoPtr,Point offsetPos)
  1072. {
  1073.     ShapeListPtr shapeList;
  1074.  
  1075.     PenNormal();
  1076.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  1077.         DrawShapeObject(shapeList,offsetPos,true);
  1078.     }
  1079. }
  1080.  
  1081.  
  1082. /* draws the shape from a shape record */
  1083.  
  1084. void DrawShapeObject(ShapeListPtr theShape,Point drawOffset,Boolean selected)
  1085. {
  1086.     if (theShape->shapeType==kBeginGroupTag) {
  1087.         DrawAnchorPoints(theShape,drawOffset,selected ? theShape->selected : false);
  1088.         if (selected)
  1089.             DSIGDrawSigner(theShape,drawOffset);
  1090.         for (theShape = theShape->subList; theShape!=nil; theShape = theShape->next)
  1091.             DrawShapeObject(theShape,drawOffset,false);
  1092.     }
  1093.     else {
  1094.         DrawCurrentShape(theShape->shapeType,theShape->anchor,theShape->destination,drawOffset);
  1095.         DrawAnchorPoints(theShape,drawOffset,selected ? theShape->selected : false);
  1096.         if (selected)
  1097.             DSIGDrawSigner(theShape,drawOffset);
  1098.     }
  1099. }
  1100.  
  1101.  
  1102. /* draws the shape from components*/
  1103.  
  1104. void DrawCurrentShape(short theShape,Point anchor,Point endPt,Point drawOffset)
  1105. {
  1106.     Rect theRect;
  1107.     Point emptyPt = {0,0};
  1108.     
  1109.     anchor.h += drawOffset.h;
  1110.     anchor.v += drawOffset.v;
  1111.     endPt.h += drawOffset.h;
  1112.     endPt.v += drawOffset.v;
  1113.     
  1114.     // draw the shape
  1115.     
  1116.     switch (theShape) {
  1117.         case kLineShape:
  1118.             MoveTo(anchor.h,anchor.v);
  1119.             LineTo(endPt.h,endPt.v);
  1120.             break;
  1121.         case kRectShape:
  1122.             SetRect(&theRect,anchor.h,anchor.v,endPt.h,endPt.v);
  1123.             FixRect(&theRect);
  1124.             FrameRect(&theRect);
  1125.             break;
  1126.         case kRoundRectShape:
  1127.             SetRect(&theRect,anchor.h,anchor.v,endPt.h,endPt.v);
  1128.             FixRect(&theRect);
  1129.             FrameRoundRect(&theRect,15,15);
  1130.             break;
  1131.         case kOvalShape:
  1132.             SetRect(&theRect,anchor.h,anchor.v,endPt.h,endPt.v);
  1133.             FixRect(&theRect);
  1134.             FrameOval(&theRect);
  1135.             break;
  1136.     }    
  1137. }
  1138.  
  1139. /* draw the anchor points for a shape */
  1140.  
  1141. void DrawAnchorPoints(ShapeListPtr theShape,Point drawOffset,Boolean selected)
  1142. {
  1143.     Rect theRect;
  1144.     Boolean fourAnchors;
  1145.     Point anchor,endPt;
  1146.     
  1147.     anchor = theShape->anchor;
  1148.     endPt = theShape->destination;
  1149.     
  1150.     if (theShape->shapeType==kLineShape)
  1151.         fourAnchors = false;
  1152.     else
  1153.         fourAnchors = true;
  1154.         
  1155.     anchor.h += drawOffset.h;
  1156.     anchor.v += drawOffset.v;
  1157.     endPt.h += drawOffset.h;
  1158.     endPt.v += drawOffset.v;
  1159.  
  1160.     SetRect(&theRect,anchor.h-kAnchorWidth,anchor.v-kAnchorWidth,
  1161.             anchor.h+kAnchorWidth,anchor.v+kAnchorWidth);
  1162.     if (selected)
  1163.         FillRect(&theRect,qd.black);
  1164.     SetRect(&theRect,endPt.h-kAnchorWidth,endPt.v-kAnchorWidth,
  1165.             endPt.h+kAnchorWidth,endPt.v+kAnchorWidth);
  1166.     if (selected)
  1167.         FillRect(&theRect,qd.black);
  1168.     if (fourAnchors) {
  1169.         SetRect(&theRect,anchor.h-kAnchorWidth,endPt.v-kAnchorWidth,
  1170.                 anchor.h+kAnchorWidth,endPt.v+kAnchorWidth);
  1171.         if (selected)
  1172.             FillRect(&theRect,qd.black);
  1173.         SetRect(&theRect,endPt.h-kAnchorWidth,anchor.v-kAnchorWidth,
  1174.                 endPt.h+kAnchorWidth,anchor.v+kAnchorWidth);
  1175.         if (selected)
  1176.             FillRect(&theRect,qd.black);
  1177.     }
  1178. }
  1179.  
  1180.  
  1181. /* erase the anchor points for a shape */
  1182.  
  1183. void EraseAnchorPoints(ShapeListPtr theShape,Point drawOffset)
  1184. {
  1185.     Point anchor,endPt;
  1186.     Rect theRect;
  1187.     Boolean fourAnchors;
  1188.     
  1189.     if (theShape->shapeType == kLineShape)
  1190.         fourAnchors = false;
  1191.     else
  1192.         fourAnchors = true;
  1193.         
  1194.     anchor.h = theShape->anchor.h + drawOffset.h;
  1195.     anchor.v = theShape->anchor.v + drawOffset.v;
  1196.     endPt.h = theShape->destination.h + drawOffset.h;
  1197.     endPt.v = theShape->destination.v + drawOffset.v;
  1198.  
  1199.     SetRect(&theRect,anchor.h-kAnchorWidth,anchor.v-kAnchorWidth,
  1200.             anchor.h+kAnchorWidth,anchor.v+kAnchorWidth);
  1201.     InvalRect(&theRect);
  1202.     SetRect(&theRect,endPt.h-kAnchorWidth,endPt.v-kAnchorWidth,
  1203.             endPt.h+kAnchorWidth,endPt.v+kAnchorWidth);
  1204.     InvalRect(&theRect);
  1205.     if (fourAnchors) {
  1206.         SetRect(&theRect,anchor.h-kAnchorWidth,endPt.v-kAnchorWidth,
  1207.                 anchor.h+kAnchorWidth,endPt.v+kAnchorWidth);
  1208.         InvalRect(&theRect);
  1209.         SetRect(&theRect,endPt.h-kAnchorWidth,anchor.v-kAnchorWidth,
  1210.                 endPt.h+kAnchorWidth,anchor.v+kAnchorWidth);
  1211.         InvalRect(&theRect);
  1212.     }
  1213. }
  1214.  
  1215.  
  1216. /* see if we hit an anchor point, and if yes, return anchor and destination points */
  1217.  
  1218. Boolean CheckHitAnchor(ShapeListPtr theShape,Point hitPt,Point offsetPos,Point *anchor,Point *endPt)
  1219. {
  1220.     Rect theRect;
  1221.     Boolean fourAnchors;
  1222.     
  1223.     hitPt.h -= offsetPos.h;
  1224.     hitPt.v -= offsetPos.v;
  1225.     
  1226.     if (theShape->selected==false)
  1227.         return false;
  1228.         
  1229.     if (theShape->shapeType == kLineShape)
  1230.         fourAnchors = false;
  1231.     else
  1232.         fourAnchors = true;
  1233.         
  1234.     *anchor = theShape->anchor;
  1235.     *endPt = theShape->destination;
  1236.  
  1237.     SetRect(&theRect,anchor->h-kAnchorWidth,anchor->v-kAnchorWidth,
  1238.             anchor->h+kAnchorWidth,anchor->v+kAnchorWidth);
  1239.     if (PtInRect(hitPt,&theRect)) {
  1240.         *anchor = theShape->destination;
  1241.         *endPt = theShape->anchor;
  1242.         return true;
  1243.     }
  1244.     
  1245.     SetRect(&theRect,endPt->h-kAnchorWidth,endPt->v-kAnchorWidth,
  1246.             endPt->h+kAnchorWidth,endPt->v+kAnchorWidth);
  1247.     if (PtInRect(hitPt,&theRect)) {
  1248.         *anchor = theShape->anchor;
  1249.         *endPt = theShape->destination;
  1250.         return true;
  1251.     }
  1252.  
  1253.     if (fourAnchors) {
  1254.     
  1255.         SetRect(&theRect,anchor->h-kAnchorWidth,endPt->v-kAnchorWidth,
  1256.                 anchor->h+kAnchorWidth,endPt->v+kAnchorWidth);
  1257.         if (PtInRect(hitPt,&theRect)) {
  1258.             anchor->h = theShape->destination.h;
  1259.             anchor->v = theShape->anchor.v;
  1260.             endPt->h = theShape->anchor.h;
  1261.             endPt->v = theShape->destination.v;
  1262.             return true;
  1263.         }
  1264.  
  1265.         SetRect(&theRect,endPt->h-kAnchorWidth,anchor->v-kAnchorWidth,
  1266.                 endPt->h+kAnchorWidth,anchor->v+kAnchorWidth);
  1267.         if (PtInRect(hitPt,&theRect)) {
  1268.             anchor->h = theShape->anchor.h;
  1269.             anchor->v = theShape->destination.v;
  1270.             endPt->h = theShape->destination.h;
  1271.             endPt->v = theShape->anchor.v;
  1272.             return true;
  1273.         }
  1274.     }
  1275.     return false;
  1276. }
  1277.  
  1278.  
  1279. /* re-orient rectangle so top-left is at top-left */
  1280.  
  1281. void FixRect(Rect *rect)
  1282. {
  1283.     short pt;
  1284.     
  1285.     if (rect->left > rect->right) {
  1286.         pt = rect->left;
  1287.         rect->left = rect->right;
  1288.         rect->right = pt;
  1289.     }
  1290.  
  1291.     if (rect->top > rect->bottom) {
  1292.         pt = rect->top;
  1293.         rect->top = rect->bottom;
  1294.         rect->bottom = pt;
  1295.     }
  1296. }
  1297.  
  1298.  
  1299. /* offset shape by delta */
  1300.  
  1301. void OffsetShape(ShapeListPtr theShape,short deltaH,short deltaV)
  1302. {
  1303.     ShapeListPtr groupList;
  1304.     
  1305.     if (theShape->shapeType == kBeginGroupTag) {
  1306.         for (groupList=theShape->subList; groupList!=nil; groupList=groupList->next)
  1307.             OffsetShape(groupList,deltaH,deltaV);
  1308.     }
  1309.     
  1310.     theShape->anchor.h += deltaH;
  1311.     theShape->anchor.v += deltaV;
  1312.     theShape->destination.h += deltaH;
  1313.     theShape->destination.v += deltaV;
  1314. }
  1315.  
  1316.  
  1317. /* add a shape to the document */
  1318.  
  1319. ShapeListPtr AddShape(short currentShape,Point anchor,Point destination,ShapeListPtr subList,
  1320.                         ShapeListPtr *shapeHead,Boolean addToEnd)
  1321. {
  1322.     ShapeListPtr newShape;
  1323.     
  1324.     newShape = NewPtrChk(sizeof(ShapeList));
  1325.     if (MemError()!=noErr) {
  1326.         DoError(MemError());
  1327.         return;
  1328.     }
  1329.     
  1330.     // note: all of this funny business with "addToEnd" is to insure that the shapes are
  1331.     // not reversed during the save/load process so that any group digital signatures will still
  1332.     // remain valid
  1333.     
  1334.     if (addToEnd && *shapeHead) {
  1335.         (*shapeHead)->next = newShape;
  1336.         newShape->next = nil;
  1337.         *shapeHead = newShape;
  1338.     }
  1339.     else {
  1340.         newShape->next = *shapeHead;
  1341.         *shapeHead = newShape;
  1342.     }
  1343.     
  1344.     newShape->anchor = anchor;
  1345.     newShape->destination = destination;
  1346.     newShape->shapeType = currentShape;
  1347.     newShape->selected = false;
  1348.     newShape->isSigned = false;
  1349.     newShape->signatureID = 0;
  1350.     newShape->subList = subList;
  1351. }
  1352.  
  1353.  
  1354. /* set up the undo op.  we only support undo for adding shapes for now */
  1355.  
  1356. void AddShapeUndo(short currentShape,Point anchor,Point destination,WindowPtr window,WInfoPtr infoPtr)
  1357. {
  1358.     ShapeList newShape;
  1359.     
  1360.     newShape.anchor = anchor;
  1361.     newShape.destination = destination;
  1362.     newShape.shapeType = currentShape;
  1363.     SetUndoCommand(window,infoPtr,&newShape);
  1364.     FixDrawMenus(window,infoPtr);
  1365. }
  1366.  
  1367.  
  1368. void RemoveTopShape(WindowPtr window,WInfoPtr infoPtr)
  1369. {
  1370.     ShapeList *shapeToKill,*shapeList;
  1371.     
  1372.     shapeList = (ShapeListPtr) infoPtr->data;
  1373.     shapeToKill = shapeList;
  1374.     InvalShapeArea(window,infoPtr,shapeToKill);
  1375.     
  1376.     infoPtr->data = shapeList->next;
  1377.     DisposPtrChk(shapeToKill);
  1378. }
  1379.  
  1380.  
  1381. void InvalShapeArea(WindowPtr window,WInfoPtr infoPtr,ShapeList *theShape)
  1382. {
  1383.     GrafPtr savePort;
  1384.     Rect shapeRect;
  1385.     Point *scrollPos;
  1386.     RgnHandle shapeRgn,scrollRgn;
  1387.     
  1388.     GetPort(&savePort);
  1389.     SetPort(window);
  1390.  
  1391.     SetRect(&shapeRect,theShape->anchor.h,theShape->anchor.v,
  1392.             theShape->destination.h,theShape->destination.v);
  1393.     FixRect(&shapeRect);
  1394.  
  1395.     scrollPos = (Point *)&infoPtr->otherData[kViewOffset];
  1396.     OffsetRect(&shapeRect,infoPtr->leftIndent-scrollPos->h,infoPtr->topIndent-scrollPos->v);
  1397.     InsetRect(&shapeRect,-5,-5);    // for slop
  1398.     shapeRgn = NewRgn();
  1399.     scrollRgn = GetScrollersRgn(&window->portRect);
  1400.     RectRgn(shapeRgn,&shapeRect);
  1401.     DiffRgn(shapeRgn,scrollRgn,shapeRgn);
  1402.     InvalRgn(shapeRgn);
  1403.     DisposeRgn(shapeRgn);
  1404.     DisposeRgn(scrollRgn);
  1405.     
  1406.     SetPort(savePort);
  1407. }
  1408.  
  1409.  
  1410. short CheckShapeSelected(WindowPtr window,WInfoPtr infoPtr)
  1411. {
  1412.     ShapeListPtr shapeList;
  1413.     short shapeCount;
  1414.     
  1415.     shapeCount = 0;
  1416.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  1417.         if (shapeList->selected)
  1418.             shapeCount++;
  1419.     }
  1420.     return shapeCount;
  1421. }
  1422.  
  1423.  
  1424. short CheckGroupSelected(WindowPtr window,WInfoPtr infoPtr)
  1425. {
  1426.     ShapeListPtr shapeList;
  1427.     
  1428.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  1429.         if (shapeList->selected && shapeList->shapeType==kBeginGroupTag)
  1430.             return true;
  1431.     }
  1432.     return false;
  1433. }
  1434.  
  1435.  
  1436. void GetGroupBounds(ShapeListPtr groupList,Point *anchor,Point *destination)
  1437. {
  1438.     anchor->h = groupList->anchor.h;
  1439.     anchor->v = groupList->anchor.v;
  1440.     destination->h = groupList->destination.h;
  1441.     destination->v = groupList->destination.v;
  1442.     
  1443.     while (groupList) {
  1444.         if (groupList->anchor.h < anchor->h)
  1445.             anchor->h = groupList->anchor.h;
  1446.         if (groupList->destination.h < anchor->h)
  1447.             anchor->h = groupList->destination.h;
  1448.         if (groupList->anchor.v < anchor->v)
  1449.             anchor->v = groupList->anchor.v;
  1450.         if (groupList->destination.v < anchor->v)
  1451.             anchor->v = groupList->destination.v;
  1452.         if (groupList->anchor.h > destination->h)
  1453.             destination->h = groupList->anchor.h;
  1454.         if (groupList->destination.h > destination->h)
  1455.             destination->h = groupList->destination.h;
  1456.         if (groupList->anchor.v > destination->v)
  1457.             destination->v = groupList->anchor.v;
  1458.         if (groupList->destination.v > destination->v)
  1459.             destination->v = groupList->destination.v;
  1460.             
  1461.         groupList = groupList->next;
  1462.     }
  1463. }
  1464.  
  1465.  
  1466. OSErr SaveFileToTemp(WInfoPtr infoPtr,FSSpec *fSpec)
  1467. {
  1468.     OSErr err;
  1469.     long randNum;
  1470.     Str255 randStr;
  1471.     short fRefNum,resRefNum;
  1472.     
  1473.     err = FindFolder(kOnSystemDisk,kTemporaryFolderType,true,&fSpec->vRefNum,&fSpec->parID);
  1474.     if (err!=noErr)
  1475.         return err;
  1476.         
  1477.     randNum = (unsigned long) Random();
  1478.     NumToString(randNum,randStr);
  1479.     pstrcpy(fSpec->name,randStr);
  1480.     
  1481.     // create the temporary file
  1482.     
  1483.     err = FSpCreate(fSpec,kAppCreator,kDrawingType,smRoman);
  1484.     if (err==dupFNErr) {
  1485.         FSpDelete(fSpec);
  1486.         err = FSpCreate(fSpec,kAppCreator,kDrawingType,smRoman);
  1487.     }
  1488.     if (err!=noErr) {
  1489.         FSpDelete(fSpec);
  1490.         return err;
  1491.     }
  1492.     FSpCreateResFile(fSpec,kAppCreator,kDrawingType,smRoman);
  1493.     err = ResError();
  1494.     if (err!=noErr) {
  1495.         FSpDelete(fSpec);
  1496.         return err;
  1497.     }
  1498.     
  1499.     // open the temporary file
  1500.     
  1501.     err = FSpOpenDF(fSpec,fsRdWrPerm,&fRefNum);
  1502.     if (err!=noErr) {
  1503.         FSpDelete(fSpec);
  1504.         return err;
  1505.     }
  1506.     resRefNum = FSpOpenResFile(fSpec,fsRdWrPerm);
  1507.     err = ResError();
  1508.     if (err!=noErr) {
  1509.         FSClose(fRefNum);
  1510.         FSpDelete(&infoPtr->fileSpec);
  1511.         return err;
  1512.     }
  1513.     
  1514.     // save the digital signature information
  1515.     
  1516.     DSIGSaveFile(infoPtr,resRefNum,true);
  1517.     
  1518.     // save the data into the temporary file
  1519.     
  1520.     err = SaveDrawingToDisk(fRefNum,infoPtr);
  1521.  
  1522.     // close the file
  1523.     
  1524.     FSClose(fRefNum);
  1525.     CloseResFile(resRefNum);
  1526.     
  1527.     if (err!=noErr) {
  1528.         FSpDelete(fSpec);
  1529.     }
  1530.  
  1531.     return err;
  1532. }
  1533.  
  1534.  
  1535. OSErr SaveDrawingToDisk(short fRefNum,WInfoPtr infoPtr)
  1536. {
  1537.     OSErr err;
  1538.     ShapeListPtr shapeList;
  1539.     long count,totalCount;
  1540.     char hState;
  1541.     
  1542.     // set file position to start of file
  1543.     
  1544.     err = SetFPos(fRefNum,fsFromStart,0);
  1545.     if (err!=noErr)
  1546.         return err;
  1547.     totalCount = 0;
  1548.     
  1549.     // write print record
  1550.     
  1551.     count = sizeof(TPrint);
  1552.     hState = HGetState((Handle)infoPtr->printRecord);
  1553.     HLock((Handle)infoPtr->printRecord);
  1554.     err = FSWrite(fRefNum,&count,*(infoPtr->printRecord));
  1555.     totalCount += count;
  1556.     HSetState((Handle)infoPtr->printRecord,hState);
  1557.     if (err!=noErr)
  1558.         return err;
  1559.     
  1560.     // write shape information
  1561.     
  1562.     shapeList = infoPtr->data;
  1563.     err = SaveShapesToDisk(fRefNum,infoPtr->data,&totalCount);
  1564.     if (err!=noErr)
  1565.         return err;
  1566.         
  1567.     // set file length
  1568.     
  1569.     err = SetEOF(fRefNum,totalCount);
  1570.     
  1571.     return err;
  1572. }
  1573.  
  1574.  
  1575. OSErr SaveShapesToDisk(short fRefNum,ShapeListPtr shapeList,long *totalCount)
  1576. {
  1577.     long count;
  1578.     OSErr err;
  1579.     
  1580.     while (shapeList) {
  1581.         count = sizeof(ShapeList);
  1582.         err = FSWrite(fRefNum,&count,shapeList);
  1583.         *totalCount += count;
  1584.         if (err!=noErr) {
  1585.             return err;
  1586.         }
  1587.         if (shapeList->shapeType==kBeginGroupTag) {
  1588.             err = SaveShapesToDisk(fRefNum,shapeList->subList,totalCount);
  1589.             if (err!=noErr)
  1590.                 return err;
  1591.             count = sizeof(ShapeList);
  1592.             shapeList->shapeType = kEndGroupTag;
  1593.             err = FSWrite(fRefNum,&count,shapeList);
  1594.             *totalCount += count;
  1595.             shapeList->shapeType = kBeginGroupTag;
  1596.         }
  1597.         
  1598.         shapeList = shapeList->next;
  1599.     }
  1600.     return err;
  1601. }
  1602.  
  1603.  
  1604. OSErr LoadShapesFromDisk(short fRefNum,ShapeListPtr *shapeHead)
  1605. {
  1606.     long count;
  1607.     OSErr err;
  1608.     ShapeList theShape;
  1609.     ShapeListPtr newShape,endShape;
  1610.     
  1611.     endShape = *shapeHead;
  1612.     
  1613.     do {
  1614.         count = sizeof(ShapeList);
  1615.         err = FSRead(fRefNum,&count,&theShape);
  1616.         if (err==noErr) {
  1617.             if (theShape.shapeType==kBeginGroupTag) {
  1618.                 theShape.subList = nil;
  1619.                 err = LoadShapesFromDisk(fRefNum,&theShape.subList);
  1620.                 if (err==noErr) {
  1621.                     newShape = AddShape(theShape.shapeType,theShape.anchor,theShape.destination,
  1622.                                     theShape.subList,&endShape,true);
  1623.                     newShape->isSigned = theShape.isSigned;
  1624.                     newShape->signatureID = theShape.signatureID;
  1625.                 }
  1626.             }
  1627.             else if (theShape.shapeType!=kEndGroupTag) {
  1628.                 newShape = AddShape(theShape.shapeType,theShape.anchor,theShape.destination,
  1629.                                     nil,&endShape,true);
  1630.                 newShape->isSigned = theShape.isSigned;
  1631.                 newShape->signatureID = theShape.signatureID;
  1632.             }
  1633.             if (*shapeHead==nil)
  1634.                 *shapeHead = endShape;
  1635.         }
  1636.     } while (err==noErr && theShape.shapeType!=kEndGroupTag);
  1637.     return err;
  1638. }
  1639.  
  1640.  
  1641. void FixDrawMenus(WindowPtr window,WInfoPtr infoPtr)
  1642. {
  1643.     MenuHandle theMenu;
  1644.     
  1645.     FixDrawEditMenu();
  1646.     
  1647.     theMenu = GetMHandle(kShapesMenu);
  1648.     EnableAllMenuItems(theMenu);
  1649.     if (CheckShapeSelected(window,infoPtr)<2)
  1650.         DisableItem(theMenu,kGroupItem);
  1651.     if (!CheckGroupSelected(window,infoPtr))
  1652.         DisableItem(theMenu,kUngroupItem);
  1653.  
  1654.     DSIGSetupSignMenu(window,infoPtr);
  1655.     
  1656.     gMenusDirty = true;
  1657. }
  1658.  
  1659.  
  1660. void FixDrawEditMenu(void)
  1661. {
  1662.     MenuHandle theMenu;
  1663.  
  1664.     theMenu = GetMHandle(kEditMenu);
  1665.     EnableAllMenuItems(theMenu);
  1666.     if (!SetupAppUndo())
  1667.         DisableItem(theMenu,kUndoItem);
  1668.     DisableItem(theMenu,kCutItem);
  1669.     DisableItem(theMenu,kCopyItem);
  1670.     DisableItem(theMenu,kPasteItem);
  1671.     DisableItem(theMenu,kClearItem);
  1672. }